package com.lingyun.system.service.impl;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.lingyun.common.constant.ScheduleConstants;
import com.lingyun.common.corebase.GeneralEntity;
import com.lingyun.common.exception.quartz.QuartzInOperationException;
import com.lingyun.common.exception.user.CaptchaExpireException;
import com.lingyun.common.mapper.LyJobMapper;
import com.lingyun.common.pojo.LyJob;
import com.lingyun.common.utils.StringUtils;
import com.lingyun.common.vo.quartz.QuartzSearch;
import com.lingyun.common.vo.quartz.QuartzStatus;
import com.lingyun.system.quartz.QuartzConcurrentExecution;
import com.lingyun.system.quartz.QuartzDisallowConcurrentExecution;
import com.lingyun.system.service.LyJobService;
import org.quartz.*;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.text.ParseException;
import java.util.Date;

/**
 * 定时任务调度表(LyJob)表服务实现类
 *
 * @author 没事别学JAVA
 * @since 2023-01-02 20:58:26
 */
@Service("lyJobService")
public class LyJobServiceImpl extends ServiceImpl<LyJobMapper, LyJob> implements LyJobService {

    @Resource
    LyJobMapper lyJobMapper;

    @Resource
    private Scheduler scheduler;

    @Override
    public IPage<LyJob> quartzList(QuartzSearch quartzSearch) {
        Page<LyJob> page =new Page<>(quartzSearch.getCurrent(), quartzSearch.getSize());
        IPage<LyJob> ipage = lyJobMapper.quartzList(page);
        return ipage;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void quartzAdd(LyJob job) throws SchedulerException {

        // 获取到执行任务的类
        Class<? extends Job> jobClass = getQuartzJobClass(job);

        // 构建job信息
        JobDetail jobDetail = JobBuilder
                .newJob(jobClass)
                .withIdentity(JobKey.jobKey(ScheduleConstants.TASK_CLASS_NAME+job.getJobId(), job.getJobGroup()))
                .build();

        // Cron表达式调度构建器(即任务执行的时间)
        CronScheduleBuilder cron = CronScheduleBuilder.cronSchedule(job.getCronExpression());

        //根据Cron表达式构建一个Trigger
        CronTrigger trigger = TriggerBuilder
                .newTrigger()
                .withIdentity(TriggerKey.triggerKey(ScheduleConstants.TASK_CLASS_NAME+job.getJobId(), job.getJobGroup()))
                .withSchedule(cron)
                .build();

        // 放入参数，运行时的方法可以获取
        jobDetail.getJobDataMap().put(ScheduleConstants.TASK_PROPERTIES, job);

        // 判断是否存在
        if (scheduler.checkExists(JobKey.jobKey(ScheduleConstants.TASK_CLASS_NAME+job.getJobId(), job.getJobGroup()))) {
            // 防止创建时存在数据问题 先移除，然后在执行创建操作
            scheduler.deleteJob(JobKey.jobKey(ScheduleConstants.TASK_CLASS_NAME+job.getJobId(), job.getJobGroup()));
        }

        if(job.getJobStatus().equals("0")){  // 判断状态 0 运行中   1 暂停
            // 判断任务是否过期
            if (StringUtils.isNotNull(getNextExecution(job.getCronExpression()))) {
                if(job.getMisfirePolicy().equals("1")){  //立即执行
                    // 执行调度任务
                    scheduler.scheduleJob(jobDetail, trigger);
                }else if(job.getMisfirePolicy().equals("2")){ //执行一次
                    // 执行调度任务
                    scheduler.scheduleJob(jobDetail, trigger);
                    // 暂停任务
                    scheduler.pauseJob(JobKey.jobKey(ScheduleConstants.TASK_CLASS_NAME+job.getJobId(), job.getJobGroup()));
                }else if(job.getMisfirePolicy().equals("3")){ //放弃执行
                    // 暂停任务
                    scheduler.pauseJob(JobKey.jobKey(ScheduleConstants.TASK_CLASS_NAME+job.getJobId(), job.getJobGroup()));
                }else if(job.getMisfirePolicy().equals("4")) { //执行一次删除
                    // 执行调度任务
                    scheduler.scheduleJob(jobDetail, trigger);
                    // 暂停任务
                    scheduler.pauseJob(JobKey.jobKey(ScheduleConstants.TASK_CLASS_NAME+job.getJobId(), job.getJobGroup()));
                    // 删除任务
                    scheduler.deleteJob(JobKey.jobKey(ScheduleConstants.TASK_CLASS_NAME+job.getJobId(), job.getJobGroup()));
                }
            }
            insertScheduledTask(job); // 定时任务入库
        }else{
            // 暂停任务
            scheduler.pauseJob(JobKey.jobKey(ScheduleConstants.TASK_CLASS_NAME+job.getJobId(), job.getJobGroup()));
            insertScheduledTask(job); // 定时任务入库
        }
    }

    @Override
    public Integer quartzUpdate(LyJob job) {
        Integer row = 0;
        row = lyJobMapper.updateSelective(job);
        return row;
    }


    @Override
    public Integer insertScheduledTask(LyJob job) {

        // 获取创建时间
        Date create = new Date();
        // 设置创建时间
        job.setCreateTime(create);
        // 第一次入库创建时间就是更新时间
        job.setUpdateTime(create);
        return lyJobMapper.insertLyJob(job);
    }

    @Override
    public Integer quartzDelete(Long jobId) throws QuartzInOperationException, SchedulerException {

        Integer row = 0;

        // 获取到定时任务
        LyJob lyJob = lyJobMapper.queryById(jobId);

        if(lyJob.getJobStatus().equals("0")){ // 判断状态 0运行中   1暂停
            throw new QuartzInOperationException();
        }else{
            // 判断是否存在
            if (scheduler.checkExists(JobKey.jobKey(ScheduleConstants.TASK_CLASS_NAME+lyJob.getJobId(), lyJob.getJobGroup()))) {
                // 删除任务
                scheduler.deleteJob(JobKey.jobKey(ScheduleConstants.TASK_CLASS_NAME+lyJob.getJobId(), lyJob.getJobGroup()));
                // 暂停任务
                scheduler.pauseJob(JobKey.jobKey(ScheduleConstants.TASK_CLASS_NAME+lyJob.getJobId(), lyJob.getJobGroup()));
            }
            // 删除数据库中的定时任务
            row = lyJobMapper.deleteById(lyJob.getJobId());
            return row;
        }

    }

    @Override
    public Integer updateJobStatus(QuartzStatus quartzStatus) {
        Integer row = 0;
        LyJob lyJob = new LyJob(quartzStatus.getJobId(),quartzStatus.getJobStatus());
        row = lyJobMapper.updateSelective(lyJob);
        return row;
    }


    /**
     * 得到quartz任务类
     * @param jbo 执行计划
     * @return 具体执行任务类
     */
    private static Class<? extends Job> getQuartzJobClass(LyJob jbo) {

        boolean isConcurrent = "0".equals(jbo.getConcurrent());
        return isConcurrent ? QuartzConcurrentExecution.class : QuartzDisallowConcurrentExecution.class;
    }


    /**
     * 返回下一个执行时间根据给定的Cron表达式
     *
     * @param cronExpression Cron表达式
     * @return Date 下次Cron表达式执行时间
     */
    public static Date getNextExecution(String cronExpression) {

        try {
            CronExpression cron = new CronExpression(cronExpression);
            return cron.getNextValidTimeAfter(new Date(System.currentTimeMillis()));
        } catch (ParseException e) {
            throw new IllegalArgumentException(e.getMessage());
        }
    }


}
